package jobworker

import (
	"fmt"
	"gitee.com/captials-team/ubdframe/src/pkg/comag"
	"gitee.com/captials-team/ubdframe/src/pkg/metrics"
	"go.uber.org/dig"
	"time"
)

type IWorker interface {
	Name() string
	Op() *JobParam

	Interval() time.Duration   //运行的间隔
	Actions() []string         //支持的actions
	Params() map[string]string //支持的参数

	Start() //一直运行
	Stop()

	Run(int64) //只运行一次

	Debug() //debug用
	//GetRunInterval() time.Duration //实际运行的间隔
	//Tps() float64 //总tps
}

type IWorkerMonitor interface {
	SetMonitor(chan metrics.IndicData)
}

type YieldWorkerFunc func(di *dig.Container, op *JobParam) IWorker //可以允许di和op为nil
type DoWorkerActionFunc func(di *dig.Container, op *JobParam) error

func (f DoWorkerActionFunc) YieldWorkerFunc(di *dig.Container, op *JobParam) IWorker {
	return newCommonWorker(di, op, f)
}

type commonWorker struct {
	di *dig.Container
	op *JobParam
	f  DoWorkerActionFunc

	comag.StopWorker
}

func (w *commonWorker) Name() string {
	return w.op.Action
}

func (w *commonWorker) Op() *JobParam {
	return w.op
}

func (w *commonWorker) Actions() []string {
	return []string{}
}

func (w *commonWorker) Params() map[string]string {
	return nil
}

func (w *commonWorker) Start() {
	w.Run(0)
}

func (w *commonWorker) Run(count int64) {

	w.StopWorker.Start()

	if w.op == nil {
		panic(fmt.Sprintf("%s op nil", w.Name()))
	}
	if w.f == nil {
		panic(fmt.Sprintf("%s func nil", w.Name()))
	}

	ti := time.NewTicker(time.Second)
	if w.op.Interval > 0 {
		ti = time.NewTicker(w.op.Interval)
	}
	i := int64(0)
	for !w.StopWorker.Stopped() {
		i++
		select {
		case <-ti.C:
			if count > 0 && i > count {
				return
			}
			err := w.f(w.di, w.op)
			if err != nil {
				panic(err)
			}
		}
	}
}

func (w *commonWorker) Stop() {
	w.StopWorker.Stop()
}

func (w *commonWorker) Interval() time.Duration {
	return w.op.Interval
}

func (w *commonWorker) GetRunInterval() time.Duration {
	return w.op.Interval
}

func (w *commonWorker) Tps() float64 {
	return 0
}

func (w *commonWorker) Debug() {
}

func newCommonWorker(di *dig.Container, op *JobParam, f DoWorkerActionFunc) IWorker {
	return &commonWorker{
		di: di,
		op: op,
		f:  f,
	}
}
